use std::ops::{
    Add, AddAssign, Div, DivAssign,  Mul, MulAssign, Neg, Sub, SubAssign,
};


use serde::{Serialize, Deserialize};

use super::{Vector2f, Vector3f};
#[derive(Debug,Default, Clone, Copy, PartialEq, PartialOrd,Serialize, Deserialize)]
pub struct Vector4<T>
where
    T: Copy + Default  
{
    pub x: T,
    pub y: T,
    pub z: T,
    pub w: T,
}

// Addition
impl<T> Add for Vector4<T>
where
    T: Copy + Default  + Add<Output = T>
{
    type Output = Vector4<T>;

    fn add(self, other: Vector4<T>) -> Vector4<T> {
        Vector4 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        }
    }
}



// Addition Assign
impl<T> AddAssign for Vector4<T>
where
    T: Copy
        + Default
        + Add<Output = T>
{
    fn add_assign(&mut self, other: Self) {
        *self = Self {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        };
    }
}

// Addition scalar
impl<T> Add<T> for Vector4<T>
where
    T: Copy
        + Default
        + Add<Output = T>
{
    type Output = Vector4<T>;

    fn add(self, other: T) -> Self::Output {
        Vector4 {
            x: self.x + other,
            y: self.y + other,
            z: self.z + other,
            w: self.w + other,
        }
    }
}

// Addition scalar Assign
impl<T> AddAssign<T> for Vector4<T>
where
    T: Copy
        + Default
        + Add<Output = T>
{
    fn add_assign(&mut self, other: T) {
        *self = Self {
            x: self.x + other,
            y: self.y + other,
            z: self.z + other,
            w: self.w + other,
        };
    }
}

// Subtraction
impl<T> Sub for Vector4<T>
where
    T: Copy
        + Default
        + Sub<Output = T>
{
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        Vector4 {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
            w: self.w - other.w,
        }
    }
}




// Subtraction Assign
impl<T> SubAssign for Vector4<T>
where
    T: Copy
        + Default
        + Sub<Output = T>
{
    fn sub_assign(&mut self, other: Self) {
        *self = Self {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
            w: self.w - other.w,
        };
    }
}

// Subtraction scalar
impl<T> Sub<T> for Vector4<T>
where
    T: Copy
        + Default
        + Sub<Output = T>
{
    type Output = Self;

    fn sub(self, other: T) ->  Self::Output  {
        Self {
            x: self.x - other,
            y: self.y - other,
            z: self.z - other,
            w: self.w - other,
        }
    }
}

// Subtraction scalar Assign
impl<T> SubAssign<T> for Vector4<T>
where
    T: Copy
        + Default
        + Sub<Output = T>
{
    fn sub_assign(&mut self, other: T) {
        *self = Self {
            x: self.x - other,
            y: self.y - other,
            z: self.z - other,
            w: self.w - other,
        };
    }
}

// Multiplication
impl<T> Mul for Vector4<T>
where
    T: Copy
        + Default

        + Mul<Output = T>
{
    type Output = Vector4<T>;

    fn mul(self, other: Vector4<T>) -> Vector4<T> {
        Vector4 {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
            w: self.w * other.w,
        }
    }
}

// Multiplication Assign
impl<T> MulAssign for Vector4<T>
where
    T: Copy
        + Default

        + Mul<Output = T>
{
    fn mul_assign(&mut self, other: Self) {
        *self = Self {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
            w: self.w * other.w,
        };
    }
}

// Multiplication scalar
impl<T> Mul<T> for Vector4<T>
where
    T: Copy
        + Default

        + Mul<Output = T>
{
    type Output = Self;

    fn mul(self, other: T) ->  Self::Output {
        Self {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
            w: self.w * other,
        }
    }
}

// Multiplication scalar Assign
impl<T> MulAssign<T> for Vector4<T>
where
    T: Copy
        + Default
        + Mul<Output = T>
{
    fn mul_assign(&mut self, other: T) {
        *self = Self {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
            w: self.w * other,
        };

    }
}

// Division
impl<T> Div for Vector4<T>
where
    T: Copy
        + Default
        + Div<Output = T>
{
    type Output = Self;

    fn div(self, other: Vector4<T>) -> Self::Output {
        Self {
            x: self.x / other.x,
            y: self.y / other.y,
            z: self.z / other.z,
            w: self.w / other.w,
        }
    }
}

// Division Assign
impl<T> DivAssign for Vector4<T>
where
    T: Copy
        + Default
        + Div<Output = T>
{
    fn div_assign(&mut self, other: Vector4<T>) {
        *self = Self {
            x: self.x / other.x,
            y: self.y / other.y,
            z: self.z / other.z,
            w: self.w / other.w,
        };
    }
}

// Division scalar
impl<T> Div<T> for Vector4<T>
where
    T: Copy
        + Default
        + Div<Output = T>
{
    type Output = Self;

    fn div(self, other: T) -> Self::Output {
        Self {
            x: self.x / other,
            y: self.y / other,
            z: self.z / other,
            w: self.w / other,
        }
    }
}

// Division scalar Assign
impl<T> DivAssign<T> for Vector4<T>
where
    T: Copy
        + Default
        + Div<Output = T>
        + Neg<Output = T>
{
    fn div_assign(&mut self, other: T) {
        *self = Self {
            x: self.x / other,
            y: self.y / other,
            z: self.z / other,
            w: self.w / other,
        };
    }
}

// Negation
impl<T> Neg for Vector4<T>
where
    T: Copy
        + Default

        + Neg<Output = T>
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Vector4 {
            x: -self.x,
            y: -self.y,
            z: -self.z,
            w: -self.w,

        }
    }
}

impl<T> Vector4<T>
where
    T: Copy
        + Default
        + Div<Output = T>
        + Mul<Output = T>
        + Add<Output = T>
        + Div<Output = T>
        + Sub<Output = T>
 
{
  
    pub fn new(x: T, y: T, z: T , w:T) -> Vector4<T> {
        Vector4 { x, y, z ,w}
    }




  
    pub const ZERO:Vector4<f32> = Vector4{x:0.0,y:0.0 ,z: 0.0 , w:0.0};

    // dot product
    pub fn dot(&self, other: &Vector4<T>) -> T {
        self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
    }




}




pub type Vector4u = Vector4<u32>;
pub type Vector4i = Vector4<i32>;
pub type Vector4u16 = Vector4<u16>;





#[derive(Debug,Default, Clone, Copy, PartialEq, PartialOrd,Serialize, Deserialize)]
pub struct Vector4f
{
    pub x: f32,
    pub y: f32,
    pub z: f32,
    pub w: f32,
}

// Addition
impl Add for Vector4f
{
    type Output = Vector4f;

    fn add(self, other: Vector4f) -> Vector4f {
        Vector4f {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        }
    }
}



// Addition Assign
impl AddAssign for Vector4f
{
    fn add_assign(&mut self, other: Self) {
        *self = Self {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        };
    }
}

// Addition scalar
impl Add<f32> for Vector4f
{
    type Output = Vector4f;

    fn add(self, other: f32) -> Self::Output {
        Vector4f {
            x: self.x + other,
            y: self.y + other,
            z: self.z + other,
            w: self.w + other,
        }
    }
}

// Addition scalar Assign
impl AddAssign<f32> for Vector4f
{
    fn add_assign(&mut self, other: f32) {
        *self = Self {
            x: self.x + other,
            y: self.y + other,
            z: self.z + other,
            w: self.w + other,
        };
    }
}

// Subtraction
impl Sub for Vector4f
{
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        Vector4f {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
            w: self.w - other.w,
        }
    }
}




// Subtraction Assign
impl SubAssign for Vector4f
{
    fn sub_assign(&mut self, other: Self) {
        *self = Self {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
            w: self.w - other.w,
        };
    }
}

// Subtraction scalar
impl Sub<f32> for Vector4f
{
    type Output = Self;

    fn sub(self, other: f32) ->  Self::Output  {
        Self {
            x: self.x - other,
            y: self.y - other,
            z: self.z - other,
            w: self.w - other,
        }
    }
}

// Subtraction scalar Assign
impl SubAssign<f32> for Vector4f

{
    fn sub_assign(&mut self, other: f32) {
        *self = Self {
            x: self.x - other,
            y: self.y - other,
            z: self.z - other,
            w: self.w - other,
        };
    }
}

// Multiplication
impl Mul for Vector4f
{
    type Output = Vector4f;

    fn mul(self, other: Vector4f) -> Vector4f {
        Vector4f {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
            w: self.w * other.w,
        }
    }
}

// Multiplication Assign
impl MulAssign for Vector4f
{
    fn mul_assign(&mut self, other: Self) {
        *self = Self {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
            w: self.w * other.w,
        };
    }
}

// Multiplication scalar
impl Mul<f32> for Vector4f
{
    type Output = Self;

    fn mul(self, other: f32) ->  Self::Output {
        Self {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
            w: self.w * other,
        }
    }
}

// Multiplication scalar Assign
impl MulAssign<f32> for Vector4f
{
    fn mul_assign(&mut self, other: f32) {
        *self = Self {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
            w: self.w * other,
        };

    }
}

// Division
impl Div for Vector4f
{
    type Output = Self;

    fn div(self, other: Vector4f) -> Self::Output {
        Self {
            x: self.x / other.x,
            y: self.y / other.y,
            z: self.z / other.z,
            w: self.w / other.w,
        }
    }
}

// Division Assign
impl DivAssign for Vector4f
{
    fn div_assign(&mut self, other: Vector4f) {
        *self = Self {
            x: self.x / other.x,
            y: self.y / other.y,
            z: self.z / other.z,
            w: self.w / other.w,
        };
    }
}

// Division scalar
impl Div<f32> for Vector4f
{
    type Output = Self;

    fn div(self, other: f32) -> Self::Output {
        Self {
            x: self.x / other,
            y: self.y / other,
            z: self.z / other,
            w: self.w / other,
        }
    }
}

// Division scalar Assign
impl DivAssign<f32> for Vector4f
{
    fn div_assign(&mut self, other: f32) {
        *self = Self {
            x: self.x / other,
            y: self.y / other,
            z: self.z / other,
            w: self.w / other,
        };
    }
}

// Negation
impl Neg for Vector4f
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Vector4f {
            x: -self.x,
            y: -self.y,
            z: -self.z,
            w: -self.w,

        }
    }
}


impl Vector4f
{
  
    pub fn new(x: f32, y: f32, z: f32 , w:f32) -> Vector4f {
        Vector4f { x, y, z ,w}
    }

 
    // dot product
    pub fn dot(&self, other: &Vector4f) -> f32 {
        self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
    }

    pub fn xy(&self) -> Vector2f {
        Vector2f::new(self.x,self.y)
    }

    pub fn xyz(&self) -> Vector3f {
        Vector3f::new(self.x,self.y,self.z)
    }


}

impl Vector4f {
     
    pub const ZERO:Vector4f = Vector4f{x:0.0,y:0.0 ,z: 0.0 , w:0.0};

}

unsafe impl bytemuck::Pod for Vector4f {}
unsafe impl bytemuck::Zeroable for Vector4f {}